﻿#region 版权说明
/**************************************************************************
 * 文 件 名：GeneratorDataModelHelper
 * 命名空间：CodeGenerator.Core
 * 描　　述：
 * 版 本 号：V1.0.0
 * 作　　者：long
 * 创建时间：2019/5/16 18:27:10
 * CLR 版本：4.0.30319.42000
 * 机器名称：DESKTOP-PHQQ0O3
***************************************************************************	
 * 修 改 人：
 * 时    间：
 * 修改说明：
***************************************************************************
 * Copyright  2018 河南广慧会计服务有限公司 Inc. All Rights Reserved
***************************************************************************/
#endregion
using CodeGenerator.ViewModel;
using CodeGenerator.ViewModel.DbViewModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CodeGenerator.Core
{
    public class GeneratorDataModelHelper
    {
        public Main MForm { get; set; }
        public  void Build()
        {
            var tables = DbHelper.GetAllData(GeneratorCofing.Connection, GeneratorCofing.DataBase);
            var physicsProjectPath = GeneratorCofing.SavePath + "/" + GeneratorCofing.FolderProject;
            var templatePath = System.AppDomain.CurrentDomain.BaseDirectory + "/Template/";
            MForm.SetCollectInfoScrollToCaret($"--开始生成");
            var tplContent = GetPublicContent(templatePath + GeneratorCofing.TplDbModel);

            #region dbModel
            //Directory.CreateDirectory(physicsProjectPath + "/" + GeneratorCofing.FolderDbModel);
            //MForm.SetCollectInfoScrollToCaret($"--数据模型目录{GeneratorCofing.FolderDbModel}生成成功");
            //var finalContent = string.Empty;
            //foreach (var item in tables)
            //{
            //    var dbModelContent = GetPublicTableContent(tplContent,item).Replace("${MAIN_CODE}", BuildMainDbModel(item));
            //    FileHelper.SaveFile(dbModelContent, physicsProjectPath + "/" + GeneratorCofing.FolderDbModel + "/" + item.TableName.ToLower() + ".cs");
            //    MForm.SetCollectInfoScrollToCaret($"--数据模型{item.TableName.ToLower()}.cs生成成功");
            //}
            #endregion

            #region Repository
            
            Directory.CreateDirectory(physicsProjectPath + "/" + GeneratorCofing.FolderRepository);
            MForm.SetCollectInfoScrollToCaret($"--数据仓储目录{GeneratorCofing.FolderRepository}生成成功");

            #region dbentities
            tplContent = GetPublicContent(templatePath + GeneratorCofing.TplDbEntities).Replace("${MAIN_CODE}", BuildDbEntities(tables));
            FileHelper.SaveFile(tplContent, physicsProjectPath + "/" + GeneratorCofing.FolderRepository + "/" + GeneratorCofing.FileDbContext + ".cs");
            MForm.SetCollectInfoScrollToCaret($"--DBContext{GeneratorCofing.FileDbContext}.cs生成成功");
            #endregion

            #region IRepository
            tplContent = GetPublicContent(templatePath + GeneratorCofing.TplIRepository);
            FileHelper.SaveFile(tplContent, physicsProjectPath + "/" + GeneratorCofing.FolderRepository + "/I" + GeneratorCofing.FileRepositoryName + ".cs");
            MForm.SetCollectInfoScrollToCaret($"--仓储接口I{GeneratorCofing.FileRepositoryName}生成成功");
            #endregion

            #region RepositoryImpl
            tplContent = GetPublicContent(templatePath + GeneratorCofing.TplRepositoryImpl);
            FileHelper.SaveFile(tplContent, physicsProjectPath + "/" + GeneratorCofing.FolderRepository + "/" + GeneratorCofing.FileRepositoryName + "Impl.cs");
            MForm.SetCollectInfoScrollToCaret($"--仓储实现{GeneratorCofing.FileRepositoryName}Impl生成成功");
            #endregion

            #endregion

            #region viewModel
            Directory.CreateDirectory(physicsProjectPath + "/" + GeneratorCofing.FolderView);
            MForm.SetCollectInfoScrollToCaret($"--视图模型目录{GeneratorCofing.FolderView}生成成功");
            tplContent = GetPublicContent(templatePath + GeneratorCofing.TplViewModel);
            var tplQueryContent=GetPublicContent(templatePath+GeneratorCofing.TplQueryModel);
            foreach (var item in tables)
            {
                Directory.CreateDirectory(physicsProjectPath + "/" + GeneratorCofing.FolderView + "/" + item.TableName.Replace("_", ""));
                var queryModelContent = GetPublicTableContent(tplQueryContent,item);
                FileHelper.SaveFile(queryModelContent, physicsProjectPath + "/" + GeneratorCofing.FolderView + "/" + item.TableName.Replace("_", "") + "/Query" + item.TableName.Replace("_", "") + "Request.cs");
                var viewModelContent = GetPublicTableContent(tplContent,item).Replace("${MAIN_CODE}",BuildViewModel(item));
                FileHelper.SaveFile(viewModelContent, physicsProjectPath + "/" + GeneratorCofing.FolderView + "/" + item.TableName.Replace("_", "") + "/" + item.TableName.Replace("_", "") + "ViewModel.cs");
                MForm.SetCollectInfoScrollToCaret($"--视图模型{GeneratorCofing.FileRepositoryName}ViewModel.cs生成成功");
            }
            #endregion

            #region service
            Directory.CreateDirectory(physicsProjectPath + "/" + GeneratorCofing.FolderService);
            MForm.SetCollectInfoScrollToCaret($"--adminmvc目录{GeneratorCofing.FolderService}生成成功");
            var itplContent = GetPublicContent(templatePath + GeneratorCofing.TplIService);
            var tplContentImpl = GetPublicContent(templatePath + GeneratorCofing.TplServiceImpl);
            foreach (var item in tables)
            {
                Directory.CreateDirectory(physicsProjectPath + "/" + GeneratorCofing.FolderService + "/" + item.TableName.Replace("_", ""));
                var serviceContent = GetPublicTableContent(itplContent, item);
                FileHelper.SaveFile(serviceContent, physicsProjectPath + "/" + GeneratorCofing.FolderService + "/" + item.TableName.Replace("_", "") + "/I" + item.TableName.Replace("_", "") + "Service.cs");
                MForm.SetCollectInfoScrollToCaret($"--服务接口I{item.TableName.Replace("_", "")}Service.cs生成成功");
                serviceContent = GetPublicTableContent(tplContentImpl, item).Replace("${MAIN_CODE}",BuildUpdateMain(item));
                FileHelper.SaveFile(serviceContent, physicsProjectPath + "/" + GeneratorCofing.FolderService + "/" + item.TableName.Replace("_", "") + "/" + item.TableName.Replace("_", "") + "ServiceImpl.cs");
                MForm.SetCollectInfoScrollToCaret($"--服务实现{item.TableName.Replace("_", "")}ServiceImpl.cs生成成功");
            }
            #endregion

            #region controller+cshtml
            Directory.CreateDirectory(physicsProjectPath + "/" + GeneratorCofing.FolderAdminMvc);
            Directory.CreateDirectory(physicsProjectPath + "/" + GeneratorCofing.FolderAdminMvc + "/Controllers");
            Directory.CreateDirectory(physicsProjectPath + "/" + GeneratorCofing.FolderAdminMvc + "/Views");
            MForm.SetCollectInfoScrollToCaret($"--adminmvc目录{GeneratorCofing.FolderAdminMvc}生成成功");
            var ctplContent = GetPublicContent(templatePath + GeneratorCofing.TplController);

            foreach (var item in tables)
            {
                var controllerContent = GetPublicTableContent(ctplContent, item);
                FileHelper.SaveFile(controllerContent, physicsProjectPath + "/" + GeneratorCofing.FolderAdminMvc + "/Controllers/" + item.TableName.Replace("_", "") + "Controller.cs");
                MForm.SetCollectInfoScrollToCaret($"--控制器{item.TableName.Replace("_", "")}Controller.cs生成成功");

                Directory.CreateDirectory(physicsProjectPath + "/" + GeneratorCofing.FolderAdminMvc + "/Views/" + item.TableName.Replace("_", ""));
                var cshtmlContent = GetPublicContent(templatePath + GeneratorCofing.TplIndexCshtml);
                cshtmlContent = GetPublicTableContent(cshtmlContent, item)
                                                .Replace("${INDEX_TITLE}", this.BuildIndexTitle(item))
                                                .Replace("${INDEX_ITEM}", this.BuildIndexItem(item));
                FileHelper.SaveFile(cshtmlContent, physicsProjectPath + "/" + GeneratorCofing.FolderAdminMvc + "/Views/" + item.TableName.Replace("_", "") + "/Index.cshtml");
                var createContent = GetPublicContent(templatePath + GeneratorCofing.TplCreateCshtml);
                createContent = GetPublicTableContent(createContent, item).Replace("${MAIN_CODE}", BuildCshtml(item));
                FileHelper.SaveFile(createContent, physicsProjectPath + "/" + GeneratorCofing.FolderAdminMvc + "/Views/" + item.TableName.Replace("_", "") + "/Create.cshtml");
                var updateContent = GetPublicContent(templatePath + GeneratorCofing.TplUpdateCshtml);
                updateContent = GetPublicTableContent(updateContent, item).Replace("${MAIN_CODE}", BuildCshtml(item));
                FileHelper.SaveFile(updateContent, physicsProjectPath + "/" + GeneratorCofing.FolderAdminMvc + "/Views/" + item.TableName.Replace("_", "") + "/Update.cshtml");
                MForm.SetCollectInfoScrollToCaret($"--{item.TableName.Replace("_", "")}视图页面生成成功.cs生成成功");
            }

            #endregion

            MForm.SetCollectInfoScrollToCaret($"--全部生成完成");
        }

        #region dbModel

        public  string BuildMainDbModel(DbTable dt)
        {
            var result = new StringBuilder();
            var primarys = dt.AllForeignKeys.Where(e => e.PrimaryKeyTableName.ToLower().Equals(dt.TableName)).ToList();
            if (primarys != null && primarys.Count > 0)
            {
                result.Append($"public {dt.TableName}()\r\n");
                result.Append("{\r\n");
                foreach (var item in primarys)
                {
                    if (item.ForeignKeyName != item.ForeignPrimaryKeyName)
                    {
                        result.Append(@"this." + dt.TableName + " = new HashSet<" + dt.TableName + " >();\r\n");
                    }
                }
                result.Append("}\r\n");

            }
            foreach (var item in dt.dbColumns)
            {
                result.Append(string.Format(@"
                /// <summary>
		        /// {0}
		        /// </summary>
                ", item.Remark));
                if (item.IsPrimaryKey)
                {
                    result.Append("[Key]\r\n");
                }
                var nullvalue = item.CommonType.IsValueType && item.IsNullable ? "?" : "";
                result.Append("public " + item.CSharpType + nullvalue + " " + item.ColumnName + " {get; set;}\r\n");
            }

            if (primarys != null && primarys.Count > 0)
            {
                foreach (var item in primarys)
                {
                    if (item.ForeignKeyName.ToLower() == item.ForeignPrimaryKeyName.ToLower())
                    {
                        result.Append("\r\n public virtual " + item.ForeignKeyTableName + " " + item.ForeignKeyTableName + " { get; set; }");
                    }
                    else
                    {
                        result.Append("\r\n public virtual ICollection<" + item.ForeignKeyTableName + "> " + item.ForeignKeyTableName + " { get; set; }");
                    }
                }
            }

            var foreigns = dt.AllForeignKeys.Where(e => e.ForeignKeyTableName.Equals(dt.TableName)).ToList();
            if (foreigns != null && foreigns.Count > 0)
            {
                foreach (var item in foreigns)
                {
                    result.Append($"\r\n [ForeignKey(\"{item.ForeignKeyName}\")]\r\n");
                    result.Append("public virtual " + item.PrimaryKeyTableName + " " + item.PrimaryKeyTableName + " { get; set; }\r\n");

                }
            }

            return result.ToString();
        }
        #endregion

        #region Repository
        
        /// <summary>
        /// dbentities
        /// </summary>
        /// <param name="tables"></param>
        /// <returns></returns>
        public string BuildDbEntities(List<DbTable> tables)
        {
            var result = "";
            foreach (var item in tables)
            {
                result += "         public virtual DbSet<" + item.TableName+ "> " + item.TableName + " { get; set; } \r\n";
            }
            return result.Replace("_", "");

        }

        #endregion

        #region service
        public string BuildUpdateMain (DbTable dataTable)
        {
            var result = "";
            foreach (var item in dataTable.dbColumns)
            {
                if (!item.IsPrimaryKey)
                {
                    result += $"			dbEntity.{item.ColumnName} = model.{item.ColumnName};\r\n";
                }
            }
            return result;
        }
        #endregion
        #region ViewModel
        public string BuildViewModel(DbTable dbTable)
        {
            var result = "";
            foreach (var item in dbTable.dbColumns)
            {
                if (!item.IsPrimaryKey)
                {
                    result += "        [Display(Name = \""+item.Remark+"\")]\r\n";
                    if (!item.IsNullable)
                    {
                        result += "        [Required(ErrorMessage = \"{0}不能为空\")]\r\n";
                    }
                    if ("bigint,int".Split(',').Contains(item.CSharpType))
                    {
                        result += "         [Range(minimum:0,maximum:int.MaxValue,ErrorMessage =\"{0}不能小于0\")]\r\n";
                    }
                    if ("decimal,float,money,numeric".Split(',').Contains(item.CSharpType))
                    {
                        result += "         [Range(minimum:0,maximum:999999999999,ErrorMessage =\"{0}不能小于0\")]\r\n";
                    }
                    if ("char,nchar,nvarchar,varchar".Split(',').Contains(item.CSharpType))
                    {
                        result += "         [StringLength(maximumLength:"+item.CharLength+",ErrorMessage =\"{0}最大长度为{1}个字符\")]\r\n";
                    }
                }
                var nullVlaue = item.CommonType.IsValueType && item.IsNullable ? "?" : "";
                result += "        public " + item.CSharpType + nullVlaue + " " + item.ColumnName + " {get; set;}\r\n\r\n";
            }
            return result;
        }
        #endregion

        #region cshtml
        public string BuildCshtml(DbTable dbTable)
        {
            var result="";
            foreach (var item in dbTable.dbColumns)
            {
                #region pic
                if (item.ColumnName.ToLower().Contains("pic") || item.ColumnName.ToLower().Contains("avatar") || item.ColumnName.ToLower().Contains("img"))
                {
                    result += "<div class=\"form-group\" id=\"file_pics\">\r\n" +
                                "    @Html.LabelFor(e => e." + item.ColumnName + ", new { @class = \"col-sm-2 control-label\" })\r\n" +
                                "    <div class=\"col-sm-10\">\r\n" +
                                "        <!-- 上传开始 -->\r\n" +
                                "        <div class=\"upfiles previews\" id=\"file_pics_previews\">\r\n" +
                                "            @if (Model != null && !string.IsNullOrEmpty(Model." + item.ColumnName + "))\r\n" +
                                "            {\r\n" +
                                "                <div class=\"file-row dz-success\">\r\n" +
                                "                    <input type=\"hidden\" name=\"" + item.ColumnName + "\" class=\"file-value\" value=\"@Model." + item.ColumnName + "\" />\r\n" +
                                "                    <div><span class=\"preview\"><img src=\"@Model." + item.ColumnName + "\" /></span></div>\r\n" +
                                "                    <div><button type=\"button\" class=\"btn cancel delete\"><span>删除</span></button></div>\r\n" +
                                "                </div>\r\n" +
                                "            }\r\n" +
                                "            <div class=\"file-row template\">\r\n" +
                                "                <div><span class=\"preview\"><img data-dz-thumbnail src=\"#\" alt=\"\" /></span></div>\r\n" +
                                "                <div class=\"upload_error\">\r\n" +
                                "                    <div class=\"popover fade top in\" style=\"display: block;\">\r\n" +
                                "                        <div class=\"arrow\"></div>\r\n" +
                                "                        <div data-dz-errormessage class=\"popover-content\"></div>\r\n" +
                                "                    </div>\r\n" +
                                "                </div>\r\n" +
                                "                <div class=\"upload-details\">\r\n" +
                                "                    <p class=\"size\" data-dz-size></p>\r\n" +
                                "                    <div class=\"progress progress-striped active\" role=\"progressbar\" aria-valuemin=\"0\" aria-valuemax=\"100\" aria-valuenow=\"0\">\r\n" +
                                "                        <div class=\"progress-bar progress-bar-success\" style=\"width:0%;\" data-dz-uploadprogress></div>\r\n" +
                                "                    </div>\r\n" +
                                "                </div>\r\n" +
                                "                <div>\r\n" +
                                "                    <button type=\"button\" class=\"btn start\"><span>开始</span></button>\r\n" +
                                "                    <button type=\"button\" data-dz-remove class=\"btn cancel\"><span>取消</span></button>\r\n" +
                                "                    <button type=\"button\" data-dz-remove class=\"btn cancel delete\"><span>删除</span></button>\r\n" +
                                "                </div>\r\n" +
                                "            </div>\r\n" +
                                "        </div>\r\n" +
                                "        <div class=\"uploadactions\">\r\n" +
                                "            <div>\r\n" +
                                "                <span class=\"btn btn-primary fileinput-button\"><span>添加文件...</span></span>\r\n" +
                                "                <button type=\"button\" class=\"btn btn-sub start\">\r\n" +
                                "                    <span>上传全部</span>\r\n" +
                                "                </button>\r\n" +
                                "                <button type=\"button\" class=\"btn btn-sub cancel\">\r\n" +
                                "                    <span>取消全部</span>\r\n" +
                                "                </button>\r\n" +
                                "            </div>\r\n" +
                                "            <div>\r\n" +
                                "                <p class=\"fileupload-process\">\r\n" +
                                "                    <div class=\"progress progress-striped active total-progress\" role=\"progressbar\" aria-valuemin=\"0\" aria-valuemax=\"100\" aria-valuenow=\"0\">\r\n" +
                                "                        <div class=\"progress-bar progress-bar-success\" style=\"width:0%;\" data-dz-uploadprogress></div>\r\n" +
                                "                    </div>\r\n" +
                                "                </p>\r\n" +
                                "            </div>\r\n" +
                                "        </div>\r\n" +
                                "        <!-- 上传结束 -->\r\n" +
                                "    </div>\r\n" +
                                "</div>\r\n\r\n";
                    continue;
                }
                #endregion
                switch (item.ColumnType)
                {
                    case "text":
                    case "ntext":
                        result += " <div class=\"form-group\">\r\n" +
                                       "@Html.LabelFor(e => e." + item.ColumnName + ", new { @class = \"col-sm-2 control-label\" })\r\n" +
                                        "<div class=\"col-sm-10\">\r\n" +
                                          "   @Html.TextAreaFor(e => e." + item.ColumnName + ", new { @class = \"form-control ckeditor\", @rows = \"20\" })\r\n" +
                                         "    <div class=\"form-control-line\"></div>\r\n" +
                                         "    <p class=\"help-block\">@Html.ValidationMessageFor(e => e." + item.ColumnName + ")</p>\r\n" +
                                        " </div>\r\n" +
                                     "</div>\r\n\r\n";
                        break;
                    case "smallint":
                    case "tinyint":
                        result += "<div class=\"form-group\">\r\n" +
                                    "  @Html.LabelFor(e => e." + item.ColumnName + ", new { @class = \"col-sm-2 control-label\" })\r\n" +
                                    "  <div class=\"col-sm-10\">\r\n" +
                                    "      @Html.DropDownListFor(e => e." + item.ColumnName + ", " + GeneratorCofing.FolderProject + ".ServiceUtility.GetEnumSelectList<" + GeneratorCofing.FolderProject + ".GlobalConfig.CommunalStatus>(), new { @class = \"form-control\" })\r\n" +
                                    "      <small class=\"help-block\">@Html.ValidationMessageFor(e => e." + item.ColumnName + ")</small>\r\n" +
                                    "  </div>\r\n" +
                                    "</div>\r\n\r\n";
                        break;
                    case "time":
                        result += " <div class=\"form-group\">\r\n" +
                                    "    @Html.LabelFor(e => e." + item.ColumnName + ", new { @class = \"col-sm-2 control-label\" })\r\n" +
                                    "    <div class=\"col-sm-10\">\r\n" +
                                    "        @Html.TextBoxFor(e=>e." + item.ColumnName + ", \"{0:HH:mm}\", new { @data_date_format = \"HH:mm\", @class = \"form-control time-picker\", @placeholder = \"" + item.Remark + "\" })\r\n" +
                                    "        <small class=\"help-block\">@Html.ValidationMessageFor(e => e." + item.ColumnName + ")</small>\r\n" +
                                    "    </div>\r\n" +
                                    "</div>\r\n\r\n";
                        break;
                    case "smalldatetime":
                    case "datetime2":
                    case "datetime":
                        result += " <div class=\"form-group\">" +
                                    "    @Html.LabelFor(e => e." + item.ColumnName + ", new { @class = \"col-sm-2 control-label\" })\r\n" +
                                    "    <div class=\"col-sm-10\">" +
                                    "        @Html.TextBoxFor(e=>e." + item.ColumnName + ", \"{0:yyyy-MM-dd}\", new { @data_date_format = \"yyyy-MM-dd\", @class = \"form-control date-picker\", @placeholder = \"" + item.Remark + "\" })\r\n" +
                                    "        <small class=\"help-block\">@Html.ValidationMessageFor(e => e." + item.ColumnName + ")</small>\r\n" +
                                    "    </div>" +
                                    "</div>\r\n\r\n";
                        break;
                    default:
                        result += "<div class=\"form-group\">\r\n" +
                                    "    @Html.LabelFor(e => e." + item.ColumnName + ", new { @class = \"col-sm-2 control-label\" })\r\n" +
                                    "    <div class=\"col-sm-10\">\r\n" +
                                    "        @Html.TextBoxFor(e => e." + item.ColumnName + ", new { @class = \"form-control\" })\r\n" +
                                    "        <small class=\"help-block\">@Html.ValidationMessageFor(e => e." + item.ColumnName + ")</small>\r\n" +
                                    "    </div>\r\n" +
                                    "</div>\r\n\r\n";
                        break;
                }
            }
            return result;
        }

        public string BuildIndexTitle(DbTable dataTable)
        {
            var result = "";
            foreach (var item in dataTable.dbColumns)
            {
                if (!item.IsPrimaryKey)
                {
                    result += $"			<th>"+item.Remark+"</th>\r\n";
                }
            }
            return result;
        }

        public string BuildIndexItem (DbTable dataTable)
        {
            var result = "";
            foreach (var item in dataTable.dbColumns)
            {
                if (!item.IsPrimaryKey)
                {
                    result += $"			<td>" + item.ColumnName + "</td>\r\n";
                }
            }
            return result;
        }
        #endregion

        #region 公共
        public string GetPublicTableContent(string content, DbTable dt)
        {
            var primaryKey = dt.dbColumns.Where(e => e.IsPrimaryKey).FirstOrDefault();
            return new StringBuilder(content).Replace("${FILE_NAME}", dt.TableName.Replace("_", ""))
                          .Replace("${FILE_NAME_LOWER}", dt.TableName.ToLower())
                          .Replace("${PRIMARY_KEYNAME}", primaryKey.ColumnName)
                          .Replace("${DB_MODEL_Folder}", GeneratorCofing.FolderDbModel)
                          .Replace("${FILE_REMARK}", dt.TableName).ToString();
        }

        public  string GetPublicContent(string path)
        {
            return FileHelper.ReadFile(path).Replace("${CREATE_DATE}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
                                           .Replace("${AUTHOR}", "long")
                                           .Replace("${COMPANY}", $"Copyright {DateTime.Now.Year} 梦想工作室 Inc. All Rights Reserved")
                                           .Replace("${NAME_SPACE}", GeneratorCofing.FolderProject)
                                           .Replace("${DBFOLDER_NAME}", GeneratorCofing.FolderDbModel)
                                           .Replace("${VIEWMODEL_FOLDER_NAME}", GeneratorCofing.FolderView)
                                           .Replace("${SERVICE_FOLDER_NAME}", GeneratorCofing.FolderService)
                                           .Replace("${REPOSITORY_BASE_NAME}", GeneratorCofing.FileRepositoryName)
                                           .Replace("${DB_CONTEXT_NAME}", GeneratorCofing.FileDbContext)
                                           .Replace("${NAME_SPACE_ADMINMVC}",GeneratorCofing.FolderAdminMvc)
                                           .Replace("${REPOSITORY_FOLDER_NAME}", GeneratorCofing.FolderRepository);
        }
        #endregion

    }
}
